package com.thghh.ch6.graph;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;

/**
 * 点
 *
 * @author Zhikang.Peng
 * @version 1.0
 * @email thghh@qq.com
 * @date 2020/11/13 10:00
 */
public class Vertex<T> implements IVertex<T> {
    private T label;
    private List<Edge<T>> edgeList;
    private IVertex<T> previousVertex;
    private boolean visited;
    private double cost;

    public Vertex(T label) {
        this.label = label;
        edgeList = new LinkedList<>();
        visited = false;
        previousVertex = null;
        cost = 0d;
    }

    @Override
    public T getLabel() {
        return label;
    }

    @Override
    public void visit() {
        this.visited = true;
    }

    @Override
    public void unVisit() {
        this.visited = false;
    }

    @Override
    public boolean isVisited() {
        return visited;
    }

    @Override
    public boolean connect(IVertex<T> vertex, double weight) {
        boolean result = false;
        if(!this.equals(vertex)) {
            Iterator<IVertex<T>> neighbors = this.getNeighborsIterator();
            boolean duplicateEdge = false;
            while(!duplicateEdge && neighbors.hasNext()) {
                IVertex<T> nextVertex = neighbors.next();
                if(vertex.equals(nextVertex)) {
                    duplicateEdge = true;
                }
            }
            if(!duplicateEdge) {
                edgeList.add(new Edge<>(vertex, weight));
                result = true;
            }
        }
        return result;
    }

    @Override
    public boolean connect(IVertex<T> vertex) {
        return connect(vertex, 0);
    }

    @Override
    public Iterator<IVertex<T>> getNeighborsIterator() {
        return new NeighborsIterator();
    }

    @Override
    public Iterator getWeightIterator() {
        return new WeightIterator();
    }

    @Override
    public boolean hasNeighbor() {
        return !edgeList.isEmpty();
    }

    @Override
    public IVertex<T> getUnvisitedNeighbor() {
        Iterator<IVertex<T>> neighbors = getNeighborsIterator();
        while(neighbors.hasNext()) {
            IVertex nextNeighbor = neighbors.next();
            if(!nextNeighbor.isVisited())
                return nextNeighbor;
        }
        return null;
    }

    @Override
    public void setPredecessor(IVertex predecessor) {
        this.previousVertex = predecessor;
    }

    @Override
    public IVertex<T> getPredecessor() {
        return this.previousVertex;
    }

    @Override
    public boolean hasPredecessor() {
        return this.previousVertex != null;
    }

    @Override
    public void setCost(double cost) {
        this.cost = cost;
    }

    @Override
    public double getCost() {
        return cost;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null || (getClass() != obj.getClass())) {
            return false;
        }
        Vertex<T> other = (Vertex<T>) obj;
        return other.getLabel().equals(label);
    }

    @Override
    public String toString() {
        return super.toString();
    }

    private class NeighborsIterator implements Iterator<IVertex<T>> {

        private Iterator<Edge<T>> edgeIterator;

        private NeighborsIterator() {
            edgeIterator = edgeList.iterator();
        }

        @Override
        public boolean hasNext() {
            return edgeIterator.hasNext();
        }

        @Override
        public IVertex<T> next() {
            return edgeIterator.next().getVertex();
        }
    }

    private class WeightIterator implements  Iterator<Double> {

        private Iterator<Edge<T>> edgesIterator;

        private WeightIterator() {
            this.edgesIterator = edgeList.iterator();
        }

        @Override
        public boolean hasNext() {
            return edgesIterator.hasNext();
        }

        @Override
        public Double next() {
            return edgesIterator.next().getWeight();
        }
    }
}
